const through = require('through2');
const gutil = require('gulp-util');
const PluginError = gutil.PluginError;
const path = require('path');
const util = require('util');
const _ = require('lodash');
const uuid = require('node-uuid');

const PLUGIN_NAME = 'gulp-version-rev';

const DEFAULT_OPTIONS = {

  '.ftl': [
    {reg: /<script.*?\s+src="(.+?\.js)"(\s+|>)/g, pos: 1},
    {reg: /<script.*?\s+src="(<@ofbizContentUrl>.+?\.js<\/@ofbizContentUrl>)"(\s+|>)/g, pos: 1},
    {reg: /<link.*?\s+href="(.+?\.css)"(\s+|>)/g, pos: 1},
    {reg: /<link.*?\s+href="(<@ofbizContentUrl>.+?\.css<\/@ofbizContentUrl>)"(\s+|>)/g, pos: 1},
    {reg: /<img.*?\s+src="(.+?)"(\s+|\/>|>)/g, pos: 1}
  ],
  '.html': [
    {reg: /<script.*?\s+src="(.+?\.js)"(\s+|>)/g, pos: 1},
    {reg: /<link.*?\s+href="(.+?\.css)"(\s+|>)/g, pos: 1},
    {reg: /<img.*?\s+src="(.+?)"(\s+|\/>|>)/g, pos: 1}
  ],
  ignoreUrls: [],
  preprocess: {
    '.ftl': [/\$\{.+?}/g]
  },
  version: new Date().getTime()
};

function versionRev(file, options) {
  let finalOptions = Object.assign({}, DEFAULT_OPTIONS, options);

  let ext = path.extname(file.path);
  let replacerList = finalOptions[ext];

  // 如果对应后缀的文件没有响应正则表达式，直接返回该文件
  if (!replacerList || !replacerList.length) {
    return file;
  }

  // 文件内容
  let content = file.contents.toString();

  // 预处理，将所有模版方法用uuid替换
  let temples = {};
  let preprocessRegs = finalOptions.preprocess[ext];
  if (util.isArray(preprocessRegs)) {
    preprocessRegs.forEach(reg => {
      let tmps = content.match(reg);
      if (util.isArray(tmps)) {
        tmps.forEach(tmp => {
          let key = uuid.v4();
          temples[key] = tmp;
          content = content.replace(new RegExp(_.escapeRegExp(tmp), 'g'), key);
        });
      }
    });
  }

  let allUrls = [];

  // 根据正则表达式提取url
  for (let replacer of replacerList) {
    let reg = replacer.reg;

    // 匹配所有字符串
    let allMatchedString = content.match(reg);
    if (!allMatchedString) {
      continue;
    }

    for (let str of allMatchedString) {
      // 需要重新创建正则表达式，否则可能匹配失败
      let results = new RegExp(reg).exec(str);

      if (results) {
        let url = results[replacer.pos];
        if (url) {
          allUrls.push(url);
        }
      } else {
        console.error('正则不能匹配', reg, str + 'A');
      }
    }
  }

  // 过滤url, 去除ignoreUrls匹配的url
  let ignoreUrls = finalOptions.ignoreUrls;
  let urls = allUrls.filter(url => !isUrlMatch(url, ignoreUrls));

  // 去重
  urls = Array.from(new Set(urls));

  // 版本号默认时间戳
  let version = finalOptions.version;

  // 所有url增加版本号
  urls.forEach(url => {
    // 全局替换
    let reg = new RegExp(_.escapeRegExp(url), 'g');
    content = content.replace(reg, `${url}?version=${version}`);
  });

  // 还原预处理的内容
  for (let key in temples) {
    console.log(key, temples[key]);
    content = content.replace(new RegExp(_.escapeRegExp(key), 'g'), temples[key]);
  }

  file.contents = new Buffer(content);
  return file;
}

// 检查url是否匹配
function isUrlMatch(url, urlConditions) {
  for (let condition of urlConditions) {
    if (util.isString(condition)) {
      if (url === condition) {
        return true;
      }
    } else if (util.isRegExp(condition)) {
      if (condition.test(url)) {
        return true;
      }
    }
  }
  return false;
}

// 插件级别函数 (处理文件)
function gulpVersionRev(options) {

  // 创建一个让每个文件通过的 stream 通道
  return through.obj(function (file, enc, cb) {

    if (file.isStream()) {
      this.emit('error', new PluginError(PLUGIN_NAME, 'Streams are not supported!'));
      return cb();
    }

    if (file.isBuffer()) {
      file = versionRev(file, options);
    }

    // 确保文件进入下一个 gulp 插件
    this.push(file);

    cb();
  });

}

// 暴露（export）插件主函数
module.exports = gulpVersionRev;
